package gwt.immunology.server.service;

import gwt.immunology.client.service.PatientsService;
import gwt.immunology.server.converter.PatientDtoConverter;
import gwt.immunology.server.util.search.PatientSearchUtil;
import gwt.immunology.shared.GenericDto;
import gwt.immunology.shared.ResultSetDto;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import models.MedicineCard_;
import models.Patient;
import models.Patient_;
import play.Logger;
import play.modules.gwt2.GWT2Service;
import play.modules.gwt2.GWT2ServicePath;

import static gwt.immunology.shared.GenericDtoKeys.BIRTHDAY_FROM;
import static gwt.immunology.shared.GenericDtoKeys.BIRTHDAY_TO;
import static gwt.immunology.shared.GenericDtoKeys.REGISTRATION_FROM;
import static gwt.immunology.shared.GenericDtoKeys.REGISTRATION_TO;
import static gwt.immunology.shared.GenericDtoKeys.PATIENTS_COUNT;
import static gwt.immunology.shared.GenericDtoKeys.PATIENTS_SEARCH_RESULT;

@GWT2ServicePath("/immunology/patient")
public class PatientsServiceImpl extends GWT2Service implements PatientsService {

    @Override
    public GenericDto registerNewPatient(GenericDto patientDto) {
    	GenericDto result = null;
    	if (patientDto != null && !patientDto.isEmpty()) {
    	    Patient patient = PatientDtoConverter.convertGenericDtoToPatient(patientDto);
    	    Logger.info("registering new patient");
    	    patient = Patient.em().merge(patient);
    	    result = PatientDtoConverter.convertPatientToGenericDto(patient);
    	} else {
    	    Logger.warn("can't register patient  with null value");
    	}
    	return result;
    }

    @Override
    public void deletePatient(Long patientId) {
    	if (patientId != null) {
    	    Patient patient = Patient.em().find(Patient.class, patientId);
    	    if (patient != null) {
    		Logger.info("deleting patient by id = " + patientId);
    		Patient.em().remove(patient);
    	    } else {
    		Logger.warn("can't delete patient with null value");
    	    }
    	} else {
    	    Logger.warn("can't delete patient by id = " + patientId);
    	}
    }

    @Override
    public GenericDto getPatientById(Long patientId) {
    	GenericDto result = null;
    	if (patientId != null) {
    	    Logger.info("retrieving patient by id = " + patientId);
    	    Patient patient = Patient.em().find(Patient.class, patientId);
    	    result = PatientDtoConverter.convertPatientToGenericDto(patient);
    	} else {
    	    Logger.warn("can't retrieve patient by id = " + patientId);
    	}
    	return result;
    }

    @Override
    public void editPatientInfo(GenericDto patientDto) {
    	if (patientDto != null && !patientDto.isEmpty()) {
    	    Patient patient = PatientDtoConverter.convertGenericDtoToPatient(patientDto);
    	    Logger.info("editing patient with id = " + patient.patientId);
    	    Patient.em().merge(patient).save();
    	} else {
    	    Logger.warn("can't edit patient with null value");
    	}
    }

    @Override
    public ResultSetDto getAllPatients() {
		Logger.info("retrieving all patients");
		List<Patient> patients = Patient.all().fetch();
		ResultSetDto resultSet = PatientDtoConverter.convertPatientsToResultSetDto(patients);
		return resultSet;
    }

    @Override
    public GenericDto findPatients(GenericDto searchCriteria) {
		Logger.info("finding patients with search criteria: " + searchCriteria);
		CriteriaQuery<Patient> criteriaQuery = new PatientSearchUtil().createSearchCriteriaQuery(searchCriteria);
		TypedQuery<Patient> typedQuery = Patient.em().createQuery(criteriaQuery);
		List<Patient> patients = typedQuery.getResultList();

		GenericDto result = new GenericDto();
		result.put(PATIENTS_COUNT, Patient.count());
		result.put(PATIENTS_SEARCH_RESULT, PatientDtoConverter.convertPatientsToResultSetDto(patients));
		return result; 
    }

}
